#include "commando.h"
#include "ui_commando.h"
#include "SpellEffect.h"
#include "Ability.h"
#include "Rotation.h"
#include "RatingConvert.h"
#include <fstream>
#include "cmath"

Commando::Commando(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Commando)
{
    ui->setupUi(this);
    string filename = "Commando_stats.txt";
    ifstream fin (filename.c_str());
    if(fin.good()){
        Load_Stats();}
    updateStatBoxes();
}

Commando::~Commando()
{
    delete ui;
}
enum STATS {
    AIM = 0, CUNNING, STRENGTH, WILLPOWER = 3,
    CRIT, SURGE, ALACRITY , POWER , ACCURACY = 8,
    DEFENSE, SHIELD, ABSORB, ARMOR = 12,
    LEVEL, MH_ACC, OH_ACC, ENEMY_LEVEL, ENEMY_ARMOR= 17,
    SPEED,  MH_MAX, MH_MIN, OH_MAX , OH_MIN =22,
    TECH_CRIT_CHANCE , TECH_CRIT_SIZE, TECH_BONUS_HEALING, TECH_BONUS_DAMAGE = 26,
    RANGED_CRIT_CHANCE , RANGED_CRIT_SIZE, RANGED_BONUS_DAMAGE = 29,
    FORCE_CRIT_CHANCE , FORCE_CRIT_SIZE, FORCE_BONUS_HEALING, FORCE_BONUS_DAMAGE = 33,
    MELEE_CRIT_CHANCE , MELEE_CRIT_SIZE, MELEE_BONUS_DAMAGE = 36,
    TECH_POWER, FORCE_POWER = 38
};

//define global Commando variables
QString rotationOutput;
QString &rotationRef = rotationOutput;

int MP_count = 0;
int AP_count = 0;
int BI_count = 0;
int HS_count = 0;
int RC_count = 0;
int SCC_count = 0;
int MP_SCC_count = 0;
int AP_SCC_count = 0;
int HS_SCC_count = 0;

int GR_count = 0;
int FA_count = 0;
int DR_count = 0;
int HIB_count = 0;
int MV_count = 0;

//create a holder for the stats
std::vector <double> stats(39,0);

void Commando::setStats()
{
    int critBuff =0;
    int techSurgeBuff = 0;
    int rangedSurgeBuff = 0;
    int alacBuff = 0;
    int accBuff = 0;
    if(ui->tree1->isChecked()){
        critBuff = 3*(ui->skillBox_3->value());
        critBuff += 2*(ui->skillBox_2->value());
        if(ui->smugglerCheckBox->isChecked()) critBuff += 5;
        techSurgeBuff = 3*(ui->skillBox_4->value());
        alacBuff = 2*(ui->skillBox_6->value());
        if(ui->skillBox_5->value()==2) alacBuff += 5;
    }
    if(ui->tree2->isChecked()){
        alacBuff = 2*(ui->skillBox_6->value());
        if(ui->skillBox_5->value()==2) alacBuff += 5;
        accBuff = 1*(ui->skillBox_4->value());
    }

    int aim = ui->primaryBox->value();
    if(ui->consularCheckBox->isChecked()) aim *= 1.05;

    stats.at(AIM) = aim;
    stats.at(CUNNING) = ui->secondaryBox->value();
    stats.at(CRIT)= ui->critBox->value();
    stats.at(SURGE)= ui->surgeBox->value();
    stats.at(POWER)= ui->powerBox->value();
    stats.at(TECH_POWER) = ui->techBox->value();
    stats.at(ALACRITY)= ui->alacBox->value();
    stats.at(LEVEL)= ui->levelBox->value();

    stats.at(ACCURACY) = ui->accBox->value();
    stats.at(MH_MAX) = ui->MHmaxBox->value();
    stats.at(MH_MIN) = ui->MHminBox->value();
    stats.at(OH_MAX) = 0;
    stats.at(OH_MIN) = 0;
    stats.at(ENEMY_LEVEL) = ui->enemyLevelBox->value();
    stats.at(ENEMY_ARMOR) = ui->enemyArmorBox->value();

    stats.at(TECH_CRIT_CHANCE) = ( TechCritChance(stats, critBuff, true));
    stats.at(TECH_CRIT_SIZE) = ( TechCritSize(stats, techSurgeBuff));
    stats.at(SPEED) =( Speed(stats, alacBuff));
    stats.at(TECH_BONUS_HEALING) = (TechBonusHealing((stats.at(POWER)+stats.at(TECH_POWER)), stats.at(AIM)));
    stats.at(MH_ACC) = MH_Accuracy(stats, accBuff);
    stats.at(TECH_BONUS_DAMAGE) = TechBonusDamage(stats, true);
    stats.at(RANGED_CRIT_CHANCE) = ( RangedCritChance(stats, critBuff, false));
    stats.at(RANGED_CRIT_SIZE) = ( RangedCritSize(stats, 0));
    stats.at(RANGED_BONUS_DAMAGE) = RangedBonusDamage(stats, false);

}

vector <double> Commando::calculateStats(vector <double> &stats2){
    int critBuff =0;
    int techSurgeBuff = 0;
    int rangedSurgeBuff = 0;
    int alacBuff = 0;
    int accBuff = 0;
    if(ui->tree1->isChecked()){
        critBuff = 3*(ui->skillBox_3->value());
        critBuff += 2*(ui->skillBox_2->value());
        if(ui->smugglerCheckBox->isChecked()) critBuff += 5;
        techSurgeBuff = 3*(ui->skillBox_4->value());
        alacBuff = 2*(ui->skillBox_6->value());
        if(ui->skillBox_5->value()==2) alacBuff += 5;
    }
    if(ui->tree2->isChecked()){
        alacBuff = 2*(ui->skillBox_6->value());
        if(ui->skillBox_5->value()==2) alacBuff += 5;
        accBuff = 3*(ui->skillBox_4->value());
    }

    stats2.at(TECH_CRIT_CHANCE) = ( TechCritChance(stats2, critBuff, true));
    stats2.at(TECH_CRIT_SIZE) = ( TechCritSize(stats2, techSurgeBuff));
    stats2.at(SPEED) =( Speed(stats2, alacBuff));
    stats2.at(TECH_BONUS_HEALING) = (TechBonusHealing((stats2.at(POWER)+stats2.at(TECH_POWER)) ,stats2.at(AIM)));
    stats2.at(MH_ACC) = (MH_Accuracy(stats2, accBuff));
    stats2.at(TECH_BONUS_DAMAGE) = TechBonusDamage(stats2, true);
    stats2.at(RANGED_CRIT_CHANCE) = ( RangedCritChance(stats2, critBuff, false));
    stats2.at(RANGED_CRIT_SIZE) = ( RangedCritSize(stats2, rangedSurgeBuff));
    stats2.at(RANGED_BONUS_DAMAGE) = RangedBonusDamage(stats2, false);

    return stats2;
}

void Commando::updateStatBoxes()
{
    ui->accBox->setEnabled(true);
    ui->accBox_2->setEnabled(true);
    ui->accBox_3->setEnabled(true);
    ui->accuracyButton->setEnabled(true);
    ui->accLabel->setEnabled(true);
    ui->accLabel_2->setEnabled(true);
    ui->accLabel_3->setEnabled(true);
    ui->accWeightLabel->setEnabled(true);
    ui->MHaccLabel->setEnabled(true);
    ui->MHaccLabel_2->setEnabled(true);
    ui->MHmaxBox->setEnabled(true);
    ui->MHmaxLabel->setEnabled(true);
    ui->MHminBox->setEnabled(true);
    ui->MHminLabel->setEnabled(true);

    ui->enemyArmorBox->setEnabled(true);
    ui->enemyArmorLabel->setEnabled(true);
    ui->enemyLevelBox->setEnabled(true);
    ui->enemyLevelLabel->setEnabled(true);
    ui->missChanceLabel->setEnabled(true);
    ui->missChanceLabel_2->setEnabled(true);
    ui->accWeightLabel_2->setEnabled(true);
    ui->enemyDRLabel->setEnabled(true);
    ui->enemyDRLabel_2->setEnabled(true);

    if(ui->tree1->isChecked()){
        ui->accBox->setEnabled(false);
        ui->accBox_2->setEnabled(false);
        ui->accBox_3->setEnabled(false);
        ui->accuracyButton->setEnabled(false);
        ui->accLabel->setEnabled(false);
        ui->accLabel_2->setEnabled(false);
        ui->accLabel_3->setEnabled(false);
        ui->accWeightLabel->setEnabled(false);
        ui->MHaccLabel->setEnabled(false);
        ui->MHaccLabel_2->setEnabled(false);
        ui->MHmaxBox->setEnabled(false);
        ui->MHmaxLabel->setEnabled(false);
        ui->MHminBox->setEnabled(false);
        ui->MHminLabel->setEnabled(false);

        ui->enemyArmorBox->setEnabled(false);
        ui->enemyArmorLabel->setEnabled(false);
        ui->enemyLevelBox->setEnabled(false);
        ui->enemyLevelLabel->setEnabled(false);
        ui->missChanceLabel->setEnabled(false);
        ui->missChanceLabel_2->setEnabled(false);
        ui->accWeightLabel_2->setEnabled(false);
        ui->enemyDRLabel->setEnabled(false);
        ui->enemyDRLabel_2->setEnabled(false);

        ui->calcHPSButton->setText("Calculate HPS");
        ui->HPS_label->setText("HPS:");
        ui->upg1Label->setText("Item 1 HPS:");
        ui->upg2Label->setText("Item 2 HPS:");
        ui->computeAlacrityButton->setText("Compute Alacrity Curves");

        ui->csCellButton->setEnabled(true);
        ui->csCellButton->setChecked(true);
        ui->apCellButton->setEnabled(false);
        ui->pCellButton->setEnabled(false);

        //set skill tree options
        ui->skill_label_9->setVisible(true);
        ui->skillBox_9->setVisible(true);
        ui->set2pcLabel->setText("Increases Duration of Supercharge Cells by 3 seconds");
        ui->set4pcLabel->setText("Reduces Cooldown of Bacta Infusion by 3 seconds and Adv. Med Probe by 1.5 seconds ");
        ui->skill_label_1->setText("Ironsights (9% Aim)");
        ui->skill_label_2->setText("Field Training (6% Tech Crit)");
        ui->skill_label_3->setText("Special Munitions (3% Tech Crit)");
        ui->skill_label_4->setText("Potent Medicine (15% Surge)");
        ui->skill_label_5->setText("First Responder (5% Alacrity)");
        ui->skill_label_6->setText("Weapon Calibration (4% Alacrity)");
        ui->skill_label_7->setText("Cell Capacitor (RC Ammo)");
        ui->skill_label_8->setText("Field Medicine");
        ui->skill_label_9->setText("Advanced Tech (1-2% Healing)");
        ui->skillBox_1->setMaximum(3);
        ui->skillBox_2->setMaximum(3);
        ui->skillBox_3->setMaximum(1);
        ui->skillBox_4->setMaximum(5);
        ui->skillBox_5->setMaximum(2);
        ui->skillBox_6->setMaximum(2);
        ui->skillBox_7->setMaximum(2);
        ui->skillBox_8->setMaximum(2);
        ui->skillBox_9->setMaximum(2);

        ui->optionBox_4->setVisible(false);
        ui->optionLabel_4->setVisible(false);
        ui->optionBox_5->setVisible(false);
        ui->optionLabel_5->setVisible(false);
        ui->note3->setVisible(false);


    }
    if(ui->tree2->isChecked()){




    }

    setStats();
    ui->techCritChanceLabel->setText(QString::number(stats.at(TECH_CRIT_CHANCE)));
    ui->techCritSizeLabel->setText(QString::number(stats.at(TECH_CRIT_SIZE)));
    ui->rangedCritChanceLabel->setText(QString::number(stats.at(RANGED_CRIT_CHANCE)));
    ui->rangedCritSizeLabel->setText(QString::number(stats.at(RANGED_CRIT_SIZE)));
    ui->speedLabel->setText(QString::number(100*(1-stats.at(SPEED))));
    ui->bonusHealingLabel->setText(QString::number(stats.at(TECH_BONUS_HEALING)));
    ui->MHaccLabel->setText(QString::number(stats.at(MH_ACC)));
    ui->techBonusDamageLabel->setText(QString::number(stats.at(TECH_BONUS_DAMAGE)));
    ui->rangedBonusDamageLabel->setText(QString::number(stats.at(RANGED_BONUS_DAMAGE)));

    double enemyLevel = ui->enemyLevelBox->value();
    double enemyArmor = ui->enemyArmorBox->value();
    double enemyArmorDR = 100*Armor(enemyLevel, 0.0, enemyArmor);
    ui->enemyDRLabel->setText(QString::number(enemyArmorDR));
    double missChance = max(100 - (stats.at(MH_ACC) - 5*(enemyLevel - stats.at(LEVEL))),0.0);
    ui->missChanceLabel->setText(QString::number(missChance));

    //HS accuracy is acc - 10;
}

double Commando::calculateHPS(){
    double HPS = 0;
    setStats();
    double rotationTime = ui->numCasts->value();
    int numCasts = ui->numCasts->value();
    if(ui->tree1->isChecked()){
        if(ui->fixedTimeButton->isChecked()){
            HPS = combatMedicRotation(rotationTime, stats);
        }else{
            HPS = combatMedicRotation(numCasts, stats);
        }
    }
    if(ui->tree2->isChecked()){
        if(ui->fixedTimeButton->isChecked()){
            HPS = GunneryRotation(rotationTime, stats);
        }else{
            HPS = GunneryRotation(numCasts, stats);
        }
    }

    return HPS;
}

void Commando::computeAlacrity(){
    ui->castView->clear();
    ui->countView->clear();
    setStats();
    vector <double> stats2=stats;
    QString alacOutput;
    if(ui->tree1->isChecked()){
        alacOutput += "Haste%, HS SCC casts, HS Casts, SCC usages, AP+MP casts, AP+MP SCC casts, Total Casts, HPS\n\n";
    }
    if(ui->tree2->isChecked()){
        alacOutput += "Haste%, DPS, GR Casts, FA casts, DR casts, HIB casts, HS casts\n\n";
    }

    double rotationTime = ui->numCasts->value();
    int numCasts = ui->numCasts->value();
    double HPS, DPS;
    int numRotations = ui->optionBox_4->value();
    for(double m=0.0;m<39.5;m+=0.5){
        DPS = 0;
        stats2.at(SPEED)=1-(m/100);
        if(ui->tree1->isChecked()){
            if(ui->fixedTimeButton->isChecked()){
                HPS = combatMedicRotation(rotationTime,stats2);
            }else{
                HPS = combatMedicRotation(numCasts,stats2);
            }
            alacOutput += QString::number(m) +" , " + QString::number(HS_SCC_count) +" ,  " + QString::number(HS_count)
                    +" , " + QString::number(SCC_count)+" , " + QString::number(MP_count+AP_count)
                    + " , " + QString::number(MP_SCC_count + AP_SCC_count)+ " , " + QString::number(MP_count + AP_count+BI_count + HS_count)
                    +" , " + QString::number(HPS) +"\n";
        }
        if(ui->tree2->isChecked()){
            srand(1);
            for(int n=0;n<numRotations;n++){

                if(ui->fixedTimeButton->isChecked()){
                    DPS += GunneryRotation(rotationTime, stats2);
                }else{
                    DPS += GunneryRotation(numCasts, stats2);
                }
            }
            DPS = DPS/numRotations;
            alacOutput += QString::number(m) +" , " + QString::number(DPS) +" ,  " + QString::number(GR_count)
                    +" , " + QString::number(FA_count)+" , " + QString::number(DR_count)
                    + " , " + QString::number(HIB_count)+ " , " + QString::number(HS_count)+"\n";
        }
    }
    ui->countView->insertPlainText(alacOutput);
}

void Commando::getWeights(){
    //copy stats for modification
    setStats();
    vector <double> stats2 = stats;
    double baseHPS, aimHPS, cunningHPS, powerHPS, critHPS, surgeHPS, alacHPS =0, refStat=1;
    double powerWeight ,aimWeight ,cunningWeight ,critWeight ,surgeWeight ,alacWeight, accWeight;

    double statBuff = 1+0.03*(ui->skillBox_1->value());
    std::vector <double> weights(9,0);
    if(ui->tree1->isChecked()){
        for(int m=0;m<7;m++){
            stats2 = stats;
            switch(m){
            case 0:
                break;
            case 1:
                stats2.at(AIM)+= (1*statBuff);
                break;
            case 2:
                stats2.at(POWER)+=1;
                break;
            case 3:
                stats2.at(CRIT)+=1;
                break;
            case 4:
                stats2.at(SURGE)+=1;
                break;
            case 5:
                stats2.at(ALACRITY)+=1;
                break;
            case 6:
                stats2.at(CUNNING)+=1;
                break;
            default:
                break;
            }
            stats2 = calculateStats(stats2);
            if(ui->fixedTimeButton->isChecked()){
                double numCasts = ui->numCasts->value();
                weights.at(m)=combatMedicRotation(numCasts, stats2);
            }else{
                int numCasts = ui->numCasts->value();
                weights.at(m)=combatMedicRotation(numCasts, stats2);
            }

        }
        baseHPS = weights.at(0);
        aimHPS = weights.at(1) -baseHPS;
        powerHPS = weights.at(2) -baseHPS;
        critHPS = weights.at(3) -baseHPS;
        surgeHPS = weights.at(4) -baseHPS;
        alacHPS = weights.at(5) -baseHPS;
        cunningHPS = weights.at(6) -baseHPS;


        if(ui->powerButton->isChecked())refStat = powerHPS;
        if(ui->aimButton->isChecked())refStat = aimHPS;
        if(ui->critButton->isChecked())refStat = critHPS;
        if(ui->surgeButton->isChecked())refStat = surgeHPS;
        if(ui->alacrityButton->isChecked())refStat = alacHPS;
        //if(ui->accuracyButton->isChecked())refStat = accuracyDPS;
        refStat = abs(refStat);

        powerWeight = powerHPS/refStat;
        aimWeight = aimHPS/refStat;
        cunningWeight = cunningHPS/refStat;
        critWeight = critHPS/refStat;
        surgeWeight = surgeHPS/refStat;
        alacWeight = alacHPS/refStat;
    }

    if(ui->tree2->isChecked()){
        int numRotations = ui->optionBox_4->value();
        for(int m=0;m<8;m++){
            stats2 = stats;
            switch(m){
            case 0:
                break;
            case 1:
                stats2.at(AIM)+= (1*statBuff);
                break;
            case 2:
                stats2.at(POWER)+=1;
                break;
            case 3:
                stats2.at(CRIT)+=1;
                break;
            case 4:
                stats2.at(SURGE)+=1;
                break;
            case 5:
                stats2.at(ALACRITY)+=1;
                break;
            case 6:
                stats2.at(CUNNING)+=1;
                break;
            case 7:
                stats2.at(ACCURACY)+=1;
                break;
            default:
                break;
            }
            stats2 = calculateStats(stats2);
            srand(1);
            for(int n=0;n<numRotations;n++){
                if(ui->fixedTimeButton->isChecked()){
                    double numCasts = ui->numCasts->value();
                    weights.at(m)+=GunneryRotation(numCasts, stats2);
                }else{
                    int numCasts = ui->numCasts->value();
                    weights.at(m)+=GunneryRotation(numCasts, stats2);
                }
            }

        }
        double baseDPS = weights.at(0)/numRotations;
        double aimDPS = weights.at(1)/numRotations -baseDPS;
        double powerDPS = weights.at(2)/numRotations -baseDPS;
        double critDPS = weights.at(3)/numRotations -baseDPS;
        double surgeDPS = weights.at(4)/numRotations -baseDPS;
        double alacDPS = weights.at(5)/numRotations -baseDPS;
        double cunningDPS = weights.at(6)/numRotations -baseDPS;
        double accDPS = weights.at(7)/numRotations -baseDPS;



        if(ui->powerButton->isChecked())refStat = powerDPS;
        if(ui->aimButton->isChecked())refStat = aimDPS;
        if(ui->critButton->isChecked())refStat = critDPS;
        if(ui->surgeButton->isChecked())refStat = surgeDPS;
        if(ui->alacrityButton->isChecked())refStat = alacDPS;
        if(ui->accuracyButton->isChecked())refStat = accDPS;
        refStat = abs(refStat);

        powerWeight = powerDPS/refStat;
        aimWeight = aimDPS/refStat;
        cunningWeight = cunningDPS/refStat;
        critWeight = critDPS/refStat;
        surgeWeight = surgeDPS/refStat;
        alacWeight = alacDPS/refStat;
        accWeight = accDPS/refStat;
    }

    ui->critWeightLabel->setText(QString::number(critWeight));
    ui->surgeWeightLabel->setText(QString::number(surgeWeight));
    ui->alacWeightLabel->setText(QString::number(alacWeight));
    ui->powerWeightLabel->setText(QString::number(powerWeight));
    ui->primaryWeightLabel->setText(QString::number(aimWeight));
    ui->secondaryWeightLabel->setText(QString::number(cunningWeight));
}

void Commando::compareUpgrades(){
    setStats();
    vector <double> stats1 = stats;
    vector <double> stats2 = stats;
    double baseHPS = 0, upg1HPS = 0, upg2HPS = 0;
    double rotationTime = ui->numCasts->value();
    int numCasts = ui->numCasts->value();
    int numRotations = ui->optionBox_4->value();

    double statBuff = 1 + 0.03*(ui->skillBox_1->value());
    if(ui->consularCheckBox->isChecked()) statBuff += 0.05;

    if(ui->tree1->isChecked()){
        if(ui->fixedTimeButton->isChecked()){
            baseHPS = combatMedicRotation(rotationTime, stats);
        }else{
            baseHPS = combatMedicRotation(numCasts, stats);
        }
    }
    if(ui->tree2->isChecked()){
        srand(1);
        for(int n=0;n<numRotations;n++){
            if(ui->fixedTimeButton->isChecked()){
                baseHPS += GunneryRotation(rotationTime, stats);
            }else{
                baseHPS += GunneryRotation(numCasts, stats);
            }
        }
        baseHPS = baseHPS/numRotations;
    }
    //populate upgrade 1
    stats1.at(AIM) += (ui->primaryBox_2->value())*statBuff;
    stats1.at(CUNNING) += ui->secondaryBox_2->value();
    stats1.at(CRIT) += ui->critBox_2->value();
    stats1.at(SURGE) += ui->surgeBox_2->value();
    stats1.at(POWER) += ui->powerBox_2->value() + ui->techBox_2->value();
    stats1.at(ALACRITY) += ui->alacBox_2->value();

    stats1 = calculateStats(stats1);

    if(ui->tree1->isChecked()){
        if(ui->fixedTimeButton->isChecked()){
            upg1HPS = combatMedicRotation(rotationTime, stats1);
        }else{
            upg1HPS = combatMedicRotation(numCasts, stats1);
        }
    }
    if(ui->tree2->isChecked()){
        srand(1);
        for(int n=0;n<numRotations;n++){
            if(ui->fixedTimeButton->isChecked()){
                upg1HPS += GunneryRotation(rotationTime, stats1);
            }else{
                upg1HPS += GunneryRotation(numCasts, stats1);
            }
        }
        upg1HPS = upg1HPS/numRotations;
    }
    //populate upgrade 2
    stats2.at(AIM) += (ui->primaryBox_3->value())*statBuff;
    stats2.at(CUNNING) += ui->secondaryBox_3->value();
    stats2.at(CRIT) += ui->critBox_3->value();
    stats2.at(SURGE) += ui->surgeBox_3->value();
    stats2.at(POWER) += ui->powerBox_3->value() + ui->techBox_2->value();
    stats2.at(ALACRITY) += ui->alacBox_3->value();

    stats2 = calculateStats(stats2);

    if(ui->tree1->isChecked()){
        if(ui->fixedTimeButton->isChecked()){
            upg2HPS = combatMedicRotation(rotationTime, stats2);
        }else{
            upg2HPS = combatMedicRotation(numCasts, stats2);
        }
    }
    if(ui->tree2->isChecked()){
        srand(1);
        for(int n=0;n<numRotations;n++){
            if(ui->fixedTimeButton->isChecked()){
                upg2HPS += GunneryRotation(rotationTime, stats2);
            }else{
                upg2HPS += GunneryRotation(numCasts, stats2);
            }
        }
        upg2HPS = upg2HPS/numRotations;
    }
    upg1HPS -= baseHPS;
    upg2HPS -= baseHPS;

    ui->HPSlabel_2->setText(QString::number(upg1HPS));
    ui->HPSlabel_3->setText(QString::number(upg2HPS));

    if(upg1HPS == upg2HPS) ui->upg3Label->setText("No difference");
    if(upg1HPS > upg2HPS) ui->upg3Label->setText("Use Item 1");
    if(upg1HPS < upg2HPS) ui->upg3Label->setText("Use Item 2");
}

void Commando::on_calcHPSButton_clicked()
{
    srand(1);
    int numRotations = ui->optionBox_4->value();
    updateStatBoxes();
    if(ui->tree1->isChecked()){
        double HPS = calculateHPS();
        ui->castView->clear();
        ui->countView->clear();
        QString countString = "MP casts: " + QString::number(MP_count)+"\nAP casts: " + QString::number(AP_count)
                +"\nHS casts: " + QString::number(HS_count)+ "\nMP casts in SCC: " + QString::number(MP_SCC_count)
                +"\nAP casts in SCC: " + QString::number(AP_SCC_count) +"\nHS casts in SCC: " + QString::number(HS_SCC_count)
                +"\nBI casts: " + QString::number(BI_count) +"\nSCC usages: " + QString::number(SCC_count)
                +"\nRC usages: " + QString::number(RC_count);
        ui->countView->insertPlainText(countString);
        ui->castView->insertPlainText(rotationOutput);
        ui->HPSlabel->setText(QString::number(HPS));
    }
    if(ui->tree2->isChecked()){
        double DPS = 0;
        for(int n=0;n<numRotations;n++){
            DPS += calculateHPS();
        }
        DPS=DPS/numRotations;
        ui->castView->clear();
        ui->countView->clear();
        QString countString = "GR casts: " + QString::number(GR_count)+"\nFA casts: " + QString::number(FA_count)
                +"\nHS casts: " + QString::number(HS_count)+ "\nDR casts: " + QString::number(DR_count)
                +"\nHIB casts: " + QString::number(HIB_count) +"\nMV casts: " + QString::number(MV_count)
                +"\nRC usages: " + QString::number(RC_count);
        ui->countView->insertPlainText(countString);
        ui->castView->insertPlainText(rotationOutput);
        ui->HPSlabel->setText(QString::number(DPS));
    }
}

double Commando::combatMedicRotation(int numCasts, vector <double> &stats){
    //define Commando abilities

    //define Combat Medic Abilities
    //Hammer Shot
    Ability HS(1.5, 0, true, 1.0, 0.0, 0.0);

    //Advanced Medical Probe
    Ability AP(1.5, 2, false, 1.94, 0.077, 0.117, 1, 0.26, 0.014, 0.014, 2);

    //Medical Probe
    Ability MP(2, 3, false, 2.72, 0.116, 0.156);

    //Bacta Infusion
    Ability BI(1.5, 0, true, 2.28, 0.084, 0.144);

    rotationOutput = "";
    MP_count = 0;
    AP_count = 0;
    BI_count = 0;
    HS_count = 0;
    RC_count = 0;
    SCC_count = 0;
    MP_SCC_count = 0;
    AP_SCC_count = 0;
    HS_SCC_count = 0;

    double knight_buff = 1;
    if (ui->knightCheckBox->isChecked()) knight_buff = 1.05;

    int RC_use = ui->optionBox_3->value();
    int RC_add = 6+ui->skillBox_7->value();
    int AP_use = ui->optionBox_2->value();
    int MP_use = ui->optionBox_1->value();
    //define set bonuses
    double reduced_AP_CD = 0;
    double reduced_BI_CD = 0;
    double increased_SCC_Duration = 0;
    if (ui->check2pcBox->isChecked()) increased_SCC_Duration = 3;
    if (ui->check4pcBox->isChecked()){
        reduced_AP_CD = 1.5;
        reduced_BI_CD = 3;
    }

    //get derived stats of value

    double critChance = stats.at(TECH_CRIT_CHANCE);
    double critSize = stats.at(TECH_CRIT_SIZE);
    double speed = stats.at(SPEED);
    double bonusHealing = stats.at(TECH_BONUS_HEALING);

    //initialize timers and counters
    double regenTime = 0;
    double AP_CD_length = 9 - reduced_AP_CD;
    double BI_CD_length = 21 - reduced_BI_CD;
    double SCC_duration = 10 + increased_SCC_Duration;
    double eTime = 0.0; //elapsed time
    double FT = 0; //time remaining on Field Triage
    int CSC = 0; //Combat Support Cell Charges
    double SCC = 0; //time remaining on Supercharge Cells
    double eHeals = 0.0; //elapsed healing
    double AP_CD = 0; //time remaining on AP Cool down
    double BI_CD = 0; //time remaining on BI Cool down
    double RC_CD = 0; //time remaining on RC cool down
    string ability = "xx";
    Ability abil;
    double rAmmo = 0;
    double tAmmo = 0;
    double tTime = 0;
    double tHeal = 0;
    double Ammo = 12.0; //Ammo level

    for (int n = 0; n < numCasts; n++) {

        if (CSC >= 30) {
            Ammo += 2;
            SCC = SCC_duration;
            SCC_count++;
            CSC = 0;
            AP_CD = 0;
            Ammo = min(max(Ammo, 0.0), 12.0);
        }
        if (Ammo < RC_use && RC_CD == 0) {
            Ammo += RC_add;
            RC_CD = 120;
            RC_count++;
            Ammo = min(max(Ammo, 0.0), 12.0);
        }
        if (SCC > 0) {
            if (FT > 0 && Ammo > (3 + 0.36 * MP.getCastTime(speed) + MP.getAmmo())) {
                tHeal = MP.getHealing(bonusHealing);
                tTime = MP.getCastTime(speed);
                tAmmo = MP.getAmmo() - 2;
                ability = "MP";
                MP_count++;
                MP_SCC_count++;

            } else {
                if (AP_CD == 0 && Ammo > (AP_use + (AP.getAmmo() - 0.36 * AP.getCastTime(speed)+ (MP.getAmmo() - 2 + MP.getCastTime(speed)*0.36)))) {
                    tHeal = AP.getHealing(bonusHealing);
                    tTime = AP.getCastTime(speed);
                    tAmmo = AP.getAmmo();
                    ability = "AP";
                    AP_count++;
                    AP_SCC_count++;
                } else {
                    if (BI_CD == 0) {
                        tHeal = BI.getHealing(bonusHealing);
                        tTime = BI.getCastTime(speed);
                        tAmmo = BI.getAmmo();
                        ability = "BI";
                        BI_count++;
                    } else {
                        tHeal = HS.getHealing(bonusHealing);
                        tTime = HS.getCastTime(speed);
                        tAmmo = HS.getAmmo();
                        ability = "HS";
                        HS_count++;
                        HS_SCC_count++;
                    }
                }
            }

        } else {
            if (FT > 0 && Ammo > (MP.getAmmo() - 2)) {
                tHeal = MP.getHealing(bonusHealing);
                tTime = MP.getCastTime(speed);
                tAmmo = MP.getAmmo() - 2;
                ability = "MP";
                CSC += 6;
                MP_count++;
            } else {
                if (AP_CD == 0 && Ammo > (8 + (AP.getAmmo() - 0.6 * AP.getCastTime(speed)))) {
                    tHeal = AP.getHealing(bonusHealing);
                    tTime = AP.getCastTime(speed);
                    tAmmo = AP.getAmmo();
                    ability = "AP";
                    AP_count++;
                } else {
                    if (BI_CD == 0) {
                        tHeal = BI.getHealing(bonusHealing);
                        tTime = BI.getCastTime(speed);
                        tAmmo = BI.getAmmo();
                        ability = "BI";
                        BI_count++;
                    } else {
                        if (Ammo > MP_use) {
                            tHeal = MP.getHealing(bonusHealing);
                            tTime = MP.getCastTime(speed);
                            tAmmo = MP.getAmmo();
                            ability = "MP";
                            CSC += 6;
                            MP_count++;
                        } else {
                            tHeal = HS.getHealing(bonusHealing);
                            tTime = HS.getCastTime(speed);
                            tAmmo = HS.getAmmo();
                            ability = "HS";
                            CSC += 3;
                            HS_count++;
                        }
                    }
                }
            }
        }

        if(ability == "MP")abil = MP;
        if(ability == "AP")abil = AP;
        if(ability == "BI")abil = BI;
        if(ability == "HS")abil = HS;


        //Factor in Critical and Surge to the average heal size
        tHeal = tHeal * ((1 - critChance / 100)+(1 + critSize / 100)*(critChance / 100));

        if (SCC > 0) //Apply Supercharge Cell buff
        {
            tHeal = tHeal * 1.1;
        } else {
            tHeal = tHeal * (1 + (CSC * 0.03 / 30)); //Apply Combat Support Cell buff
        }

        double advancedTechBuff = 1+0.01*(ui->skillBox_9->value());
        //apply knight buff
        tHeal *= knight_buff*advancedTechBuff;
        //apply field medicine buff
        if(ability == "MP"){
            tHeal *= 1+0.03*(ui->skillBox_8->value());
        }

        SCC = max(0.0, SCC - tTime);

        eHeals += tHeal; //increase elapsed healing
        eTime += tTime; // increase elapsed time

        rAmmo = getAmmoRegened(Ammo, abil, eTime, regenTime);
        Ammo += (rAmmo - tAmmo); //calculate net change in Ammo level

        //decrease time remaining on cooldowns
        RC_CD -= tTime;
        BI_CD -= tTime;
        AP_CD -= tTime;

        //ensure levels don't exceed max or min values
        SCC = max(0.0, SCC);
        AP_CD = max(0.0, AP_CD);
        BI_CD = max(0.0, BI_CD);
        RC_CD = max(0.0, RC_CD);
        FT = max(0.0, FT);
        CSC = min(30, CSC);
        Ammo = min(max(Ammo, 0.0), 12.0);

        //set cooldowns and remove procs
        if (ability == "AP") {
            FT = 10;
            if (SCC == 0) {
                AP_CD = AP_CD_length;
            } else
                AP_CD = 0;
        }
        if (ability == "MP") {
            FT = 0;
        }
        if (ability == "BI") {
            BI_CD = BI_CD_length;
        }
        if(ability == "MP")
            rotationOutput+="MP , ";
        if(ability == "AP")
            rotationOutput+="AP , ";
        if(ability == "BI")
            rotationOutput+="BI , ";
        if(ability == "HS")
            rotationOutput+="HS , ";
        rotationOutput+= QString::number(Ammo) + " , " + QString::number(tTime) + " , " + QString::number(tHeal)/* + " , " + QString::number(SCC) + " , " + QString::number(FT)*/ + "\n";
    }
    double HPS = eHeals / eTime;

    return HPS;
}

double Commando::combatMedicRotation(double rotationTime, vector <double> &stats){
    //define Commando abilities

    //define Combat Medic Abilities
    //Hammer Shot
    Ability HS(1.5, 0, true, 1.0, 0.0, 0.0);

    //Advanced Medical Probe
    Ability AP(1.5, 2, false, 1.94, 0.077, 0.117, 1, 0.26, 0.014, 0.014, 2);

    //Medical Probe
    Ability MP(2, 3, false, 2.72, 0.116, 0.156);

    //Bacta Infusion
    Ability BI(1.5, 0, true, 2.28, 0.084, 0.144);

    rotationOutput = "";
    MP_count = 0;
    AP_count = 0;
    BI_count = 0;
    HS_count = 0;
    RC_count = 0;
    SCC_count = 0;
    MP_SCC_count = 0;
    AP_SCC_count = 0;
    HS_SCC_count = 0;

    double knight_buff = 1;
    if (ui->knightCheckBox->isChecked()) knight_buff = 1.05;

    int RC_use = ui->optionBox_3->value();
    int RC_add = 6+ui->skillBox_7->value();
    int AP_use = ui->optionBox_2->value();
    int MP_use = ui->optionBox_1->value();
    //define set bonuses
    double reduced_AP_CD = 0;
    double reduced_BI_CD = 0;
    double increased_SCC_Duration = 0;
    if (ui->check2pcBox->isChecked()) increased_SCC_Duration = 3;
    if (ui->check4pcBox->isChecked()){
        reduced_AP_CD = 1.5;
        reduced_BI_CD = 3;
    }

    //get derived stats of value

    double critChance = stats.at(TECH_CRIT_CHANCE);
    double critSize = stats.at(TECH_CRIT_SIZE);
    double speed = stats.at(SPEED);
    double bonusHealing = stats.at(TECH_BONUS_HEALING);

    //initialize timers and counters
    double regenTime = 0;
    double AP_CD_length = 9 - reduced_AP_CD;
    double BI_CD_length = 21 - reduced_BI_CD;
    double SCC_duration = 10 + increased_SCC_Duration;
    double eTime = 0.0; //elapsed time
    double FT = 0; //time remaining on Field Triage
    int CSC = 0; //Combat Support Cell Charges
    if(ui->burstButton->isChecked())
    {CSC = 30;}
    double SCC = 0; //time remaining on Supercharge Cells
    double eHeals = 0.0; //elapsed healing
    double AP_CD = 0; //time remaining on AP Cool down
    double BI_CD = 0; //time remaining on BI Cool down
    double RC_CD = 0; //time remaining on RC cool down
    string ability = "xx";
    Ability abil;
    double rAmmo = 0;
    double tAmmo = 0;
    double tTime = 0;
    double tHeal = 0;
    double Ammo = 12.0; //Ammo level

    while(eTime < rotationTime) {

        if ((CSC >= 30)&&(Ammo !=12)) {
            Ammo += 2;
            SCC = SCC_duration;
            SCC_count++;
            CSC = 0;
            AP_CD = 0;
            Ammo = min(max(Ammo, 0.0), 12.0);
        }
        if (Ammo < RC_use && RC_CD == 0) {
            Ammo += RC_add;
            RC_CD = 120;
            RC_count++;
            Ammo = min(max(Ammo, 0.0), 12.0);
        }
        if (SCC > 0) {
            if (FT > 0 && Ammo > (3 + 0.36 * MP.getCastTime(speed) + MP.getAmmo())) {
                tHeal = MP.getHealing(bonusHealing);
                tTime = MP.getCastTime(speed);
                tAmmo = MP.getAmmo() - 2;
                ability = "MP";
                MP_count++;
                MP_SCC_count++;

            } else {
                if (AP_CD == 0 && Ammo > (AP_use + (AP.getAmmo() - 0.36 * AP.getCastTime(speed)+ (MP.getAmmo() - 2 + MP.getCastTime(speed)*0.36)))) {
                    tHeal = AP.getHealing(bonusHealing);
                    tTime = AP.getCastTime(speed);
                    tAmmo = AP.getAmmo();
                    ability = "AP";
                    AP_count++;
                    AP_SCC_count++;
                } else {
                    if (BI_CD == 0) {
                        tHeal = BI.getHealing(bonusHealing);
                        tTime = BI.getCastTime(speed);
                        tAmmo = BI.getAmmo();
                        ability = "BI";
                        BI_count++;
                    } else {
                        tHeal = HS.getHealing(bonusHealing);
                        tTime = HS.getCastTime(speed);
                        tAmmo = HS.getAmmo();
                        ability = "HS";
                        HS_count++;
                        HS_SCC_count++;
                    }
                }
            }

        } else {
            if (FT > 0 && Ammo > (MP.getAmmo() - 2)) {
                tHeal = MP.getHealing(bonusHealing);
                tTime = MP.getCastTime(speed);
                tAmmo = MP.getAmmo() - 2;
                ability = "MP";
                CSC += 6;
                MP_count++;
            } else {
                if (AP_CD == 0 && Ammo > (8 + (AP.getAmmo() - 0.6 * AP.getCastTime(speed)))) {
                    tHeal = AP.getHealing(bonusHealing);
                    tTime = AP.getCastTime(speed);
                    tAmmo = AP.getAmmo();
                    ability = "AP";
                    AP_count++;
                } else {
                    if (BI_CD == 0) {
                        tHeal = BI.getHealing(bonusHealing);
                        tTime = BI.getCastTime(speed);
                        tAmmo = BI.getAmmo();
                        ability = "BI";
                        BI_count++;
                    } else {
                        if (Ammo > MP_use) {
                            tHeal = MP.getHealing(bonusHealing);
                            tTime = MP.getCastTime(speed);
                            tAmmo = MP.getAmmo();
                            ability = "MP";
                            CSC += 6;
                            MP_count++;
                        } else {
                            tHeal = HS.getHealing(bonusHealing);
                            tTime = HS.getCastTime(speed);
                            tAmmo = HS.getAmmo();
                            ability = "HS";
                            CSC += 3;
                            HS_count++;
                        }
                    }
                }
            }
        }

        if(ability == "MP")abil = MP;
        if(ability == "AP")abil = AP;
        if(ability == "BI")abil = BI;
        if(ability == "HS")abil = HS;

        //Factor in Critical and Surge to the average heal size
        tHeal = tHeal * ((1 - critChance / 100)+(1 + critSize / 100)*(critChance / 100));

        if (SCC > 0) //Apply Supercharge Cell buff
        {
            tHeal = tHeal * 1.1;
        } else {
            tHeal = tHeal * (1 + (CSC * 0.03 / 30)); //Apply Combat Support Cell buff
        }

        double advancedTechBuff = 1+0.01*(ui->skillBox_9->value());
        //apply knight buff
        tHeal *= knight_buff*advancedTechBuff;
        //apply field medicine buff
        if(ability == "MP"){
            tHeal *= 1+0.03*(ui->skillBox_8->value());
        }

        SCC = max(0.0, SCC - tTime);

        eHeals += tHeal; //increase elapsed healing
        eTime += tTime; // increase elapsed time

        rAmmo = getAmmoRegened(Ammo, abil, eTime, regenTime);
        Ammo += (rAmmo - tAmmo); //calculate net change in Ammo level

        //decrease time remaining on cooldowns
        RC_CD -= tTime;
        BI_CD -= tTime;
        AP_CD -= tTime;

        //ensure levels don't exceed max or min values
        SCC = max(0.0, SCC);
        AP_CD = max(0.0, AP_CD);
        BI_CD = max(0.0, BI_CD);
        RC_CD = max(0.0, RC_CD);
        FT = max(0.0, FT);
        CSC = min(30, CSC);
        Ammo = min(max(Ammo, 0.0), 12.0);

        //set cooldowns and remove procs
        if (ability == "AP") {
            FT = 10;
            if (SCC == 0) {
                AP_CD = AP_CD_length;
            } else
                AP_CD = 0;
        }
        if (ability == "MP") {
            FT = 0;
        }
        if (ability == "BI") {
            BI_CD = BI_CD_length;
        }
        if(ability == "MP")
            rotationOutput+="MP , ";
        if(ability == "AP")
            rotationOutput+="AP , ";
        if(ability == "BI")
            rotationOutput+="BI , ";
        if(ability == "HS")
            rotationOutput+="HS , ";
        rotationOutput+= QString::number(Ammo) + " , " + QString::number(tTime) + " , " + QString::number(tHeal)/* + " , " + QString::number(SCC) + " , " + QString::number(FT)*/ + "\n";
    }
    double HPS = eHeals / eTime;

    return HPS;
}

double Commando::GunneryRotation(double rotationTime, vector <double> &stats)
{
    rotationOutput.clear();
    //define set bonuses
    double GR_crit_bonus = 0;
    double HIB_cost_reduction = 1;
    if (ui->check2pcBox->isChecked()) GR_crit_bonus = 0.15;
    if (ui->check2pcBox->isChecked()) HIB_cost_reduction = 1;

    int RC_use = ui->optionBox_3->value();
    int RC_add = 6+ui->skillBox_7->value();
    int HS_use = ui->optionBox_2->value();
    int MV_use = ui->optionBox_1->value();

    GR_count = 0;
    DR_count = 0;
    FA_count = 0;
    HIB_count = 0;
    MV_count = 0;
    RC_count = 0;
    HS_count = 0;

    //define abilities
    //Grav Round
    // Ability(float cast, int cost, bool instant);
    //Ability.effect.setValues(double coeff, double stdMin, double stdMax, double amountModPercent)
    Ability GR(1.5,3,false); //tech
    GR.effect1.setValues(2.11, 0.18, 0.24);
    GR.effect2.setValues(0, 0, 0);
    //Full Auto
    //cooldown 18s
    Ability FA(3,2,false); //ranged
    FA.effect1.setValues(1.05, 0.105, 0.105, 3, -0.3);
    FA.effect2.setValues(0, 0, 0);
    //Demolition Round
    Ability DR(1.5,2,true); //tech
    DR.effect1.setValues(2, 0.17, 0.23);
    DR.effect2.setValues(0, 0, 0);
    //High Impact Bolt
    Ability HIB(1.5,2,true); //ranged
    HIB.effect1.setValues(1.9, 0.19, 0.19, 1, 0.27);
    HIB.effect2.setValues(0, 0, 0);
    //Hammer Shot
    Ability HS(1.5, 0, true, true); //ranged
    //double coeff, double stdMin, double stdMax, int numTicks, double amountModPercent
    HS.effect1.setValues(1,1,5, 1, -1);
    HS.effect2.setValues(0, 0, 0);
    //WeaponDamage: Slots=>[ PrimaryRanged ], Coefficient=>1, FlurryBlowsMax=>1,
    //AmountModifierFixedMax=>5, AmountModifierFixedMin=>1,
    //AmountModifierPercent=>-1, IgnoreDualWieldModifier=>1, FlurryBlowsMin=>1

    //Mortar Volley
    Ability MV(3,2,false); //tech
    MV.effect1.setValues(1.58, 0.128, 0.188, 3);
    MV.effect2.setValues(0,0,0);

    //get derived stats of value
    double techCritChance = stats.at(TECH_CRIT_CHANCE);
    double techCritSize = stats.at(TECH_CRIT_SIZE);
    double techBonusDamage = stats.at(TECH_BONUS_DAMAGE);
    double rangedCritChance = stats.at(RANGED_CRIT_CHANCE);
    double rangedCritSize = stats.at(RANGED_CRIT_SIZE);
    double rangedBonusDamage = stats.at(RANGED_BONUS_DAMAGE);
    double speed = stats.at(SPEED);

    double MH_max = stats.at(MH_MAX);
    double MH_min = stats.at(MH_MIN);
    double MH_acc = stats.at(MH_ACC);
    double OH_max = stats.at(OH_MAX);
    double OH_min = stats.at(OH_MIN);
    double OH_acc = stats.at(OH_ACC);

    //initialize timers and counters
    double eTime = 0.0; //elapsed time
    double eDam = 0.0; //elapsed damage
    double regenTime = 0.0;

    double FA_CD = 0; //time remaining on FA Cool down
    double HIB_CD = 0; //time remaining on HIB Cool down
    double DR_CD = 0; //time remaining on DR Cool down
    double MV_CD = 0; //time remaining on MV Cool down
    double RC_CD = 0; //time remaining on RC cool down
    double RCP_CD_time = 120 - 15*(ui->skillBox_3->value());
    double RCP_CD = 0; //time remaining on Reserve Powercell cooldown
    double proc_CD = 0; //Curtain of Fire ICD
    string ability = "xx"; //name of ability used
    double rAmmo = 0; //Ammo regened during casting
    double tAmmo = 0; //Ammo cost of the ability
    double tTime = 0; //cast time of the ability
    double tDam = 0; //damage done by the ability
    double Ammo = 12.0; //Ammo level
    int grav_vortex_count = 0; //number of stacks of grav vortex
    double gv_time_remaining = 0; //time left on grav vortex
    int charged_barrel_count = 0;
    Ability abil;
    bool proc;
    bool ammo_proc;
    double ammo_proc_CD = 0;
    bool use_DR = false;
    if((ui->skillBox_9->value())==1.0){
        use_DR = true;
    }


    double enemyLevel = ui->enemyLevelBox->value();
    double enemyArmor = ui->enemyArmorBox->value();
    double enemyArmorDR = 0;

    double armorPen = 0;

    int openingAmmo = ui->optionBox_5->value();
    //Perform Opening Rotation
    //GR X3
    int m = 0;
    if(ui->burstButton->isChecked()){
        grav_vortex_count = 5;
    }else{
        while ( m <8){
            switch(m){
            case 0:
            case 1:
            case 2:{
                if(Ammo > openingAmmo){
                    tDam = GR.getDamage(techBonusDamage, MH_max, MH_min, OH_max, OH_min);
                    tTime = GR.getCastTime(speed);
                    tAmmo = GR.getAmmo();
                    abil = GR;
                    ability = "GR";
                    m++;
                    break;
                }else{
                    tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                    tTime = HS.getCastTime(speed);
                    tAmmo = HS.getAmmo();
                    abil = HS;
                    ability = "HS";
                    break;
                }
            }
            case 3:
                if(Ammo > openingAmmo){
                    tDam = FA.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                    tTime = FA.getCastTime(speed);
                    tAmmo = FA.getAmmo();
                    abil = FA;
                    ability = "FA";
                    m++;
                    break;
                }else{
                    tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                    tTime = HS.getCastTime(speed);
                    tAmmo = HS.getAmmo();
                    abil = HS;
                    ability = "HS";
                    break;
                }
            case 4:
                if(Ammo > openingAmmo){
                    if(use_DR == true){
                    tDam = DR.getDamage(techBonusDamage, MH_max, MH_min, OH_max, OH_min);
                    tTime = DR.getCastTime(speed);
                    tAmmo = DR.getAmmo();
                    abil = DR;
                    m++;
                    ability = "DR";
                    //DR
                    }else{
                        m++;
                    }
                    break;
                }else{
                    tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                    tTime = HS.getCastTime(speed);
                    tAmmo = HS.getAmmo();
                    abil = HS;
                    ability = "HS";
                    break;
                }
            case 5:
            case 6:
                if(Ammo > openingAmmo){
                    tDam = GR.getDamage(techBonusDamage, MH_max, MH_min, OH_max, OH_min);
                    tTime = GR.getCastTime(speed);
                    tAmmo = GR.getAmmo();
                    abil = GR;
                    ability = "GR";
                    m++;
                    break;
                }else{
                    tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                    tTime = HS.getCastTime(speed);
                    tAmmo = HS.getAmmo();
                    abil = HS;
                    ability = "HS";
                    break;
                }
            case 7:
                if(Ammo > openingAmmo){
                    tDam = HIB.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                    tTime = HIB.getCastTime(speed);
                    tAmmo = HIB.getAmmo()-HIB_cost_reduction;
                    abil = HIB;
                    ability = "HIB";
                    m++;
                    break;
                }else{
                    tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                    tTime = HS.getCastTime(speed);
                    tAmmo = HS.getAmmo();
                    abil = HS;
                    ability = "HS";
                    break;
                }
            }
            //factor in crit
            if(ability == "GR"){
                tDam = tDam * ((1 - (techCritChance / 100)-GR_crit_bonus)+(1 + techCritSize / 100)*(GR_crit_bonus+techCritChance / 100));
                tDam = tDam*(1+0.03*(ui->skillBox_8->value()));
                GR_count++;
            }
            if(ability == "FA"){
                tDam = tDam * ((1 - rangedCritChance / 100)+(1 + 0.3 + rangedCritSize / 100)*(rangedCritChance / 100));
                tDam = tDam*1.33;
                FA_count++;
            }
            if(ability == "DR"){
                tDam = tDam * ((1 - techCritChance / 100)+(1 + 0.3 + techCritSize / 100)*(techCritChance / 100));
                tDam = tDam*(1+0.03*(ui->skillBox_8->value())+0.05*grav_vortex_count);
                DR_count++;
            }
            if(ability == "HIB"){
                tDam = tDam * ((1 - rangedCritChance / 100)+(1 + rangedCritSize / 100)*(rangedCritChance / 100));
                HIB_count++;
            }
            if(ability == "HS"){
                tDam = tDam * ((1 - rangedCritChance / 100)+(1 + rangedCritSize / 100)*(rangedCritChance / 100));
                HS_count++;
            }
            //account for all procs and stacked buffs
            if(ability == "GR"){
                proc = Proc(30);
                if(ammo_proc_CD == 0){
                    ammo_proc = Proc(techCritChance);}
                if(proc == true){
                    FA_CD = 0;
                    proc_CD = 6;
                }
                gv_time_remaining = 15;
                grav_vortex_count += 1;
                grav_vortex_count = min(grav_vortex_count,5);
                charged_barrel_count += 1;
                charged_barrel_count = min(charged_barrel_count,5);
            }
            if(ability == "FA" && proc == true){
                proc = false;
                tDam = tDam * 1.25;
            }
            if(ability == "HIB"){
                tDam = tDam * (1+0.06*charged_barrel_count);
                charged_barrel_count= 0;
            }
            if((ability == "FA")&&ammo_proc_CD == 0.0){
                ammo_proc = Proc(rangedCritChance);
            }
            if((ability == "DR")&&ammo_proc_CD == 0.0){
                ammo_proc = Proc(techCritChance);
            }
            //update all cooldowns
            if(ability != "GR")
            {
                gv_time_remaining = max(gv_time_remaining-tTime,0.0);
            }
            FA_CD = max(FA_CD-tTime,0.0);
            HIB_CD = max(HIB_CD-tTime,0.0);
            DR_CD = max(DR_CD-tTime,0.0);
            MV_CD = max(MV_CD-tTime,0.0);
            RC_CD = max(RC_CD-tTime,0.0);
            RCP_CD = max(RCP_CD-tTime,0.0);
            proc_CD = max(proc_CD-tTime,0.0);
            ammo_proc_CD = max(ammo_proc_CD-tTime,0.0);
            //set cooldown for last ability
            if(ability == "FA")
            {
                FA_CD = 15;
            }
            if(ability == "HIB")
            {
                HIB_CD = 15;
            }
            if(ability == "DR")
            {
                DR_CD = 15;
            }
            if(ability == "MV")
            {
                MV_CD = 60;
            }
            //acount for enemy armor
            armorPen = 0;
            if(ui->apCellButton->isChecked()){
                armorPen += .35;
            }
            armorPen += 0.04*grav_vortex_count;
            enemyArmor = (ui->enemyArmorBox->value())*(1-armorPen);
            enemyArmorDR = Armor(enemyLevel, 0.0, enemyArmor);
            tDam = tDam * (1-enemyArmorDR);
            eDam += tDam;
            eTime += tTime;
            rAmmo = getAmmoRegened(Ammo, abil, eTime, regenTime);
            if(ammo_proc == true){
                rAmmo +=1;
                ammo_proc_CD = 3;
                ammo_proc = false;
            }
            //update Ammo and elapsed time/damage counters
            Ammo += (rAmmo - tAmmo);
            Ammo = min(max(Ammo, 0.0), 12.0);

            if(ability == "FA")
                rotationOutput+="FA , ";
            if(ability == "GR")
                rotationOutput+="GR , ";
            if(ability == "HIB")
                rotationOutput+="HIB , ";
            if(ability == "DR")
                rotationOutput+="DR , ";
            if(ability == "HS")
                rotationOutput+="HS , ";
            rotationOutput+= QString::number(Ammo) + " , " + QString::number(tTime) + " , " + QString::number(tDam)+ "\n";

        }
    }
    while(eTime < rotationTime){
        //RC
        if (Ammo < RC_use && RC_CD == 0) {
            Ammo += RC_add;
            RC_CD = 120;
            RC_count++;
            Ammo = min(max(Ammo, 0.0), 12.0);
        }
        //RCP w/ MV
        if ((Ammo < MV_use) && (RCP_CD == 0)&&(MV_CD == 0)) {
            MV_CD = 60;
            RCP_CD = RCP_CD_time;
            tDam = MV.getDamage(techBonusDamage, MH_max, MH_min, OH_max, OH_min);
            tTime = MV.getCastTime(speed);
            tAmmo = MV.getAmmo();
            abil = MV;
            ability = "MV";
        }else{
            if((Ammo < HS_use)&& (RC_CD!=0)){ // HS if ammo below option
                tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                tTime = HS.getCastTime(speed);
                tAmmo = HS.getAmmo();
                abil = HS;
                ability = "HS";
            }else{
                if(FA_CD==0){ // FA
                    tDam = FA.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                    tTime = FA.getCastTime(speed);
                    tAmmo = FA.getAmmo();
                    abil = FA;
                    ability = "FA";
                }else{
                    if((DR_CD==0)&&(use_DR == true)){
                        tDam = DR.getDamage(techBonusDamage, MH_max, MH_min, OH_max, OH_min);
                        tTime = DR.getCastTime(speed);
                        tAmmo = DR.getAmmo();
                        abil = DR;
                        ability = "DR";
                    }else{
                        if((/*(ui->check4pcBox->isChecked())||*/(charged_barrel_count==5))&&(HIB_CD==0)){
                            tDam = HIB.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                            tTime = HIB.getCastTime(speed);
                            tAmmo = HIB.getAmmo()-HIB_cost_reduction;
                            abil = HIB;
                            ability = "HIB";
                        }else{if(Ammo>=GR.getAmmo()){
                            tDam = GR.getDamage(techBonusDamage, MH_max, MH_min, OH_max, OH_min);
                            tTime = GR.getCastTime(speed);
                            tAmmo = GR.getAmmo();
                            abil = GR;
                            ability = "GR";
                            }else{
                                tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                                tTime = HS.getCastTime(speed);
                                tAmmo = HS.getAmmo();
                                abil = HS;
                                ability = "HS";
                            }
                        }
                    }
                }
            }
        }
        //factor in crit
        if(ability == "GR"){
            tDam = tDam * ((1 - (techCritChance / 100)-GR_crit_bonus)+(1 + techCritSize / 100)*(GR_crit_bonus+techCritChance / 100));
            tDam = tDam*(1+0.03*(ui->skillBox_8->value()));
            GR_count++;
        }
        if(ability == "FA"){
            tDam = tDam * ((1 - rangedCritChance / 100)+(1 + 0.3 + rangedCritSize / 100)*(rangedCritChance / 100));
            tDam = tDam*1.33;
            FA_count++;
        }
        if(ability == "DR"){
            tDam = tDam * ((1 - techCritChance / 100)+(1 + 0.3 + techCritSize / 100)*(techCritChance / 100));
            tDam = tDam*(1+0.03*(ui->skillBox_8->value())+0.05*grav_vortex_count);
            DR_count++;
        }
        if(ability == "HIB"){
            tDam = tDam * ((1 - rangedCritChance / 100)+(1 + rangedCritSize / 100)*(rangedCritChance / 100));
            HIB_count++;
        }
        if(ability == "MV"){
            tDam = tDam * ((1 - (techCritChance / 100))+(1 + techCritSize / 100)*(techCritChance / 100));
            MV_count++;
        }
        if(ability == "HS"){
            tDam = tDam * ((1 - rangedCritChance / 100)+(1 + rangedCritSize / 100)*(rangedCritChance / 100));
            HS_count++;
        }

        //account for all procs and stacked buffs
        if(ability == "GR"){
            proc = Proc(30);
            if(ammo_proc_CD == 0){
                ammo_proc = Proc(techCritChance);}
            if(proc == true){
                FA_CD = 0;
                proc_CD = 6;
            }
            gv_time_remaining = 15;
            grav_vortex_count += 1;
            grav_vortex_count = min(grav_vortex_count,5);
            charged_barrel_count += 1;
            charged_barrel_count = min(charged_barrel_count,5);
        }
        if(ability == "FA" && proc == true){
            proc = false;
            tDam = tDam * 1.25;
        }
        if(ability == "HIB"){
            tDam = tDam * (1+0.06*charged_barrel_count);
            charged_barrel_count = 0;
        }
        if((ability == "FA")&&ammo_proc_CD == 0.0){
            ammo_proc = Proc(rangedCritChance);
        }
        if((ability == "DR")&&ammo_proc_CD == 0.0){
            ammo_proc = Proc(techCritChance);
        }
        //update all cooldowns
        if(ability != "GR")
        {
            gv_time_remaining = max(gv_time_remaining-tTime,0.0);
        }
        FA_CD = max(FA_CD-tTime,0.0);
        HIB_CD = max(HIB_CD-tTime,0.0);
        DR_CD = max(DR_CD-tTime,0.0);
        MV_CD = max(MV_CD-tTime,0.0);
        RC_CD = max(RC_CD-tTime,0.0);
        RCP_CD = max(RCP_CD-tTime,0.0);
        proc_CD = max(proc_CD-tTime,0.0);
        ammo_proc_CD = max(ammo_proc_CD-tTime,0.0);
        //set cooldown for last ability
        if(ability == "FA")
        {
            FA_CD = 15;
        }
        if(ability == "HIB")
        {
            HIB_CD = 15;
        }
        if(ability == "DR")
        {
            DR_CD = 15;
        }
        if(ability == "MV")
        {
            MV_CD = 60;
        }
        //acount for enemy armor
        armorPen = 0;
        if(ui->apCellButton->isChecked()){
            armorPen += .35;
        }
        armorPen += 0.04*grav_vortex_count;
        enemyArmor = (ui->enemyArmorBox->value())*(1-armorPen);
        enemyArmorDR = Armor(enemyLevel, 0.0, enemyArmor);
        tDam = tDam * (1-enemyArmorDR);

        eDam += tDam;
        eTime += tTime;
        rAmmo = getAmmoRegened(Ammo, abil, eTime, regenTime);
        if(ammo_proc == true){
            rAmmo +=1;
            ammo_proc_CD = 3;
            ammo_proc = false;
        }
        //update Ammo and elapsed time/damage counters
        Ammo += (rAmmo - tAmmo);
        Ammo = min(max(Ammo, 0.0), 12.0);

        if(ability == "FA")
            rotationOutput+="FA , ";
        if(ability == "GR")
            rotationOutput+="GR , ";
        if(ability == "HIB")
            rotationOutput+="HIB , ";
        if(ability == "DR")
            rotationOutput+="DR , ";
        if(ability == "HS")
            rotationOutput+="HS , ";
        if(ability == "MV")
            rotationOutput+="MV , ";
        rotationOutput+= QString::number(Ammo) + " , " + QString::number(tTime) + " , " + QString::number(tDam)+ "\n";

    }
    return eDam/eTime;
}

double Commando::GunneryRotation(int numCasts, vector <double> &stats)
{
    rotationOutput.clear();
    //define set bonuses
    double GR_crit_bonus = 0;
    double HIB_cost_reduction = 1;
    if (ui->check2pcBox->isChecked()) GR_crit_bonus = 0.15;
    if (ui->check2pcBox->isChecked()) HIB_cost_reduction = 1;

    int RC_use = ui->optionBox_3->value();
    int RC_add = 6+ui->skillBox_7->value();
    int HS_use = ui->optionBox_2->value();
    int MV_use = ui->optionBox_1->value();

    GR_count = 0;
    DR_count = 0;
    FA_count = 0;
    HIB_count = 0;
    MV_count = 0;
    RC_count = 0;
    HS_count = 0;

    //define abilities
    //Grav Round
    // Ability(float cast, int cost, bool instant);
    //Ability.effect.setValues(double coeff, double stdMin, double stdMax, double amountModPercent)
    Ability GR(1.5,3,false); //tech
    GR.effect1.setValues(2.11, 0.18, 0.24);
    GR.effect2.setValues(0, 0, 0);
    //Full Auto
    //cooldown 18s
    Ability FA(3,2,false); //ranged
    FA.effect1.setValues(1.05, 0.105, 0.105, 3, -0.3);
    FA.effect2.setValues(0, 0, 0);
    //Demolition Round
    Ability DR(1.5,2,true); //tech
    DR.effect1.setValues(2, 0.17, 0.23);
    DR.effect2.setValues(0, 0, 0);
    //High Impact Bolt
    Ability HIB(1.5,2,true); //ranged
    HIB.effect1.setValues(1.9, 0.19, 0.19, 1, 0.27);
    HIB.effect2.setValues(0, 0, 0);
    Ability HS(1.5, 0, true, true); //ranged
    HS.effect1.setValues(1,1,5, 1, -1);
    HS.effect2.setValues(0, 0, 0);

    //Mortar Volley
    Ability MV(3,2,false); //tech
    MV.effect1.setValues(1.58, 0.128, 0.188, 3);
    MV.effect2.setValues(0,0,0);

    //get derived stats of value
    double techCritChance = stats.at(TECH_CRIT_CHANCE);
    double techCritSize = stats.at(TECH_CRIT_SIZE);
    double techBonusDamage = stats.at(TECH_BONUS_DAMAGE);
    double rangedCritChance = stats.at(RANGED_CRIT_CHANCE);
    double rangedCritSize = stats.at(RANGED_CRIT_SIZE);
    double rangedBonusDamage = stats.at(RANGED_BONUS_DAMAGE);
    double speed = stats.at(SPEED);

    double MH_max = stats.at(MH_MAX);
    double MH_min = stats.at(MH_MIN);
    double MH_acc = stats.at(MH_ACC);
    double OH_max = stats.at(OH_MAX);
    double OH_min = stats.at(OH_MIN);
    double OH_acc = stats.at(OH_ACC);

    //initialize timers and counters
    double eTime = 0.0; //elapsed time
    double eDam = 0.0; //elapsed damage
    double regenTime = 0.0;

    double FA_CD = 0; //time remaining on FA Cool down
    double HIB_CD = 0; //time remaining on HIB Cool down
    double DR_CD = 0; //time remaining on DR Cool down
    double MV_CD = 0; //time remaining on MV Cool down
    double RC_CD = 0; //time remaining on RC cool down
    double RCP_CD_time = 120 - 15*(ui->skillBox_3->value());
    double RCP_CD = 0; //time remaining on Reserve Powercell cooldown
    double proc_CD = 0; //Curtain of Fire ICD
    string ability = "xx"; //name of ability used
    double rAmmo = 0; //Ammo regened during casting
    double tAmmo = 0; //Ammo cost of the ability
    double tTime = 0; //cast time of the ability
    double tDam = 0; //damage done by the ability
    double Ammo = 12.0; //Ammo level
    int grav_vortex_count = 0; //number of stacks of grav vortex
    double gv_time_remaining = 0; //time left on grav vortex
    int charged_barrel_count = 0;
    Ability abil;
    bool proc;
    bool ammo_proc;
    double ammo_proc_CD = 0;
    bool use_DR = false;
    if((ui->skillBox_9->value())==1.0){
        use_DR = true;
    }

    double enemyLevel = ui->enemyLevelBox->value();
    double enemyArmor = ui->enemyArmorBox->value();
    double enemyArmorDR = 0;

    double armorPen = 0;

    int openingAmmo = ui->optionBox_5->value();
    //Perform Opening Rotation
    //GR X3
    int m = 0;
    while ( m <8){
        switch(m){
        case 0:
        case 1:
        case 2:{
            if(Ammo > openingAmmo){
                tDam = GR.getDamage(techBonusDamage, MH_max, MH_min, OH_max, OH_min);
                tTime = GR.getCastTime(speed);
                tAmmo = GR.getAmmo();
                abil = GR;
                ability = "GR";
                m++;
                break;
            }else{
                tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                tTime = HS.getCastTime(speed);
                tAmmo = HS.getAmmo();
                abil = HS;
                ability = "HS";
                break;
            }
        }
        case 3:
            if(Ammo > openingAmmo){
                tDam = FA.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                tTime = FA.getCastTime(speed);
                tAmmo = FA.getAmmo();
                abil = FA;
                ability = "FA";
                m++;
                break;
            }else{
                tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                tTime = HS.getCastTime(speed);
                tAmmo = HS.getAmmo();
                abil = HS;
                ability = "HS";
                break;
            }
        case 4:
            if(Ammo > openingAmmo){
                if(use_DR == true){
                tDam = DR.getDamage(techBonusDamage, MH_max, MH_min, OH_max, OH_min);
                tTime = DR.getCastTime(speed);
                tAmmo = DR.getAmmo();
                abil = DR;
                m++;
                ability = "DR";
                //DR
                }
                else{
                    m++;
                }
                break;
            }else{
                tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                tTime = HS.getCastTime(speed);
                tAmmo = HS.getAmmo();
                abil = HS;
                ability = "HS";
                break;
            }
        case 5:
        case 6:
            if(Ammo > openingAmmo){
                tDam = GR.getDamage(techBonusDamage, MH_max, MH_min, OH_max, OH_min);
                tTime = GR.getCastTime(speed);
                tAmmo = GR.getAmmo();
                abil = GR;
                ability = "GR";
                m++;
                break;
            }else{
                tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                tTime = HS.getCastTime(speed);
                tAmmo = HS.getAmmo();
                abil = HS;
                ability = "HS";
                break;
            }
        case 7:
            if(Ammo > openingAmmo){
                tDam = HIB.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                tTime = HIB.getCastTime(speed);
                tAmmo = HIB.getAmmo()-HIB_cost_reduction;
                abil = HIB;
                ability = "HIB";
                m++;
                break;
            }else{
                tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                tTime = HS.getCastTime(speed);
                tAmmo = HS.getAmmo();
                abil = HS;
                ability = "HS";
                break;
            }
        }
        //factor in crit
        if(ability == "GR"){
            tDam = tDam * ((1 - (techCritChance / 100)-GR_crit_bonus)+(1 + techCritSize / 100)*(GR_crit_bonus+techCritChance / 100));
            tDam = tDam*(1+0.03*(ui->skillBox_8->value()));
            GR_count++;
        }
        if(ability == "FA"){
            tDam = tDam * ((1 - rangedCritChance / 100)+(1 + 0.3 + rangedCritSize / 100)*(rangedCritChance / 100));
            tDam = tDam*1.33;
            FA_count++;
        }
        if(ability == "DR"){
            tDam = tDam * ((1 - techCritChance / 100)+(1 + 0.3 + techCritSize / 100)*(techCritChance / 100));
            tDam = tDam*(1+0.03*(ui->skillBox_8->value())+0.05*grav_vortex_count);
            DR_count++;
        }
        if(ability == "HIB"){
            tDam = tDam * ((1 - rangedCritChance / 100)+(1 + rangedCritSize / 100)*(rangedCritChance / 100));
            HIB_count++;
        }
        if(ability == "HS"){
            tDam = tDam * ((1 - rangedCritChance / 100)+(1 + rangedCritSize / 100)*(rangedCritChance / 100));
            HS_count++;
        }
        //account for all procs and stacked buffs
        if(ability == "GR"){
            proc = Proc(30);
            if(ammo_proc_CD == 0){
                ammo_proc = Proc(techCritChance);}
            if(proc == true){
                FA_CD = 0;
                proc_CD = 6;
            }
            gv_time_remaining = 15;
            grav_vortex_count += 1;
            grav_vortex_count = min(grav_vortex_count,5);
            charged_barrel_count += 1;
            charged_barrel_count = min(charged_barrel_count,5);
        }
        if(ability == "FA" && proc == true){
            proc = false;
            tDam = tDam * 1.25;
        }
        if(ability == "HIB"){
            tDam = tDam * (1+0.06*charged_barrel_count);
        }
        if((ability == "FA")&&ammo_proc_CD == 0.0){
            ammo_proc = Proc(rangedCritChance);
        }
        if((ability == "DR")&&ammo_proc_CD == 0.0){
            ammo_proc = Proc(techCritChance);
        }
        //update all cooldowns
        if(ability != "GR")
        {
            gv_time_remaining = max(gv_time_remaining-tTime,0.0);
        }
        FA_CD = max(FA_CD-tTime,0.0);
        HIB_CD = max(HIB_CD-tTime,0.0);
        DR_CD = max(DR_CD-tTime,0.0);
        MV_CD = max(MV_CD-tTime,0.0);
        RC_CD = max(RC_CD-tTime,0.0);
        RCP_CD = max(RCP_CD-tTime,0.0);
        proc_CD = max(proc_CD-tTime,0.0);
        ammo_proc_CD = max(ammo_proc_CD-tTime,0.0);
        //set cooldown for last ability
        if(ability == "FA")
        {
            FA_CD = 15;
        }
        if(ability == "HIB")
        {
            HIB_CD = 15;
        }
        if(ability == "DR")
        {
            DR_CD = 15;
        }
        if(ability == "MV")
        {
            MV_CD = 60;
        }
        //acount for enemy armor
        armorPen = 0;
        if(ui->apCellButton->isChecked()){
            armorPen += .35;
        }
        armorPen += 0.04*grav_vortex_count;
        enemyArmor = (ui->enemyArmorBox->value())*(1-armorPen);
        enemyArmorDR = Armor(enemyLevel, 0.0, enemyArmor);
        tDam = tDam * (1-enemyArmorDR);
        eDam += tDam;
        eTime += tTime;
        rAmmo = getAmmoRegened(Ammo, abil, eTime, regenTime);
        if(ammo_proc == true){
            rAmmo +=1;
            ammo_proc_CD = 3;
            ammo_proc = false;
        }
        //update Ammo and elapsed time/damage counters
        Ammo += (rAmmo - tAmmo);
        Ammo = min(max(Ammo, 0.0), 12.0);

        if(ability == "FA")
            rotationOutput+="FA , ";
        if(ability == "GR")
            rotationOutput+="GR , ";
        if(ability == "HIB")
            rotationOutput+="HIB , ";
        if(ability == "DR")
            rotationOutput+="DR , ";
        if(ability == "HS")
            rotationOutput+="HS , ";
        rotationOutput+= QString::number(Ammo) + " , " + QString::number(tTime) + " , " + QString::number(tDam)+ "\n";

    }

    numCasts -= (GR_count+FA_count+HIB_count+DR_count+HS_count);
    for(int n=0;n<numCasts;n++){
        //RC
        if (Ammo < RC_use && RC_CD == 0) {
            Ammo += RC_add;
            RC_CD = 120;
            RC_count++;
            Ammo = min(max(Ammo, 0.0), 12.0);
        }
        //RCP w/ MV
        if ((Ammo < MV_use) && (RCP_CD == 0)&&(MV_CD == 0)) {
            MV_CD = 60;
            RCP_CD = RCP_CD_time;
            tDam = MV.getDamage(techBonusDamage, MH_max, MH_min, OH_max, OH_min);
            tTime = MV.getCastTime(speed);
            tAmmo = MV.getAmmo();
            abil = MV;
            ability = "MV";
        }else{
            if((Ammo < HS_use)&& (RC_CD!=0)){ // HS if ammo below option
                tDam = HS.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                tTime = HS.getCastTime(speed);
                tAmmo = HS.getAmmo();
                abil = HS;
                ability = "HS";
            }else{
                if(FA_CD==0){ // FA
                    tDam = FA.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                    tTime = FA.getCastTime(speed);
                    tAmmo = FA.getAmmo();
                    abil = FA;
                    ability = "FA";
                }else{
                    if((DR_CD==0)&&(use_DR == true)){
                        tDam = DR.getDamage(techBonusDamage, MH_max, MH_min, OH_max, OH_min);
                        tTime = DR.getCastTime(speed);
                        tAmmo = DR.getAmmo();
                        abil = DR;
                        ability = "DR";
                    }else{
                        if(((ui->check4pcBox->isChecked())||(charged_barrel_count==5))&&(HIB_CD==0)){
                            tDam = HIB.getDamage(rangedBonusDamage, MH_max, MH_min, OH_max, OH_min);
                            tTime = HIB.getCastTime(speed);
                            tAmmo = HIB.getAmmo()-HIB_cost_reduction;
                            abil = HIB;
                            ability = "HIB";
                        }else{
                            tDam = GR.getDamage(techBonusDamage, MH_max, MH_min, OH_max, OH_min);
                            tTime = GR.getCastTime(speed);
                            tAmmo = GR.getAmmo();
                            abil = GR;
                            ability = "GR";
                        }
                    }
                }
            }
        }
        //factor in crit
        if(ability == "GR"){
            tDam = tDam * ((1 - (techCritChance / 100)-GR_crit_bonus)+(1 + techCritSize / 100)*(GR_crit_bonus+techCritChance / 100));
            tDam = tDam*(1+0.03*(ui->skillBox_8->value()));
            GR_count++;
        }
        if(ability == "FA"){
            tDam = tDam * ((1 - rangedCritChance / 100)+(1 + 0.3 + rangedCritSize / 100)*(rangedCritChance / 100));
            tDam = tDam*1.33;
            FA_count++;
        }
        if(ability == "DR"){
            tDam = tDam * ((1 - techCritChance / 100)+(1 + 0.3 + techCritSize / 100)*(techCritChance / 100));
            tDam = tDam*(1+0.03*(ui->skillBox_8->value())+0.05*grav_vortex_count);
            DR_count++;
        }
        if(ability == "HIB"){
            tDam = tDam * ((1 - rangedCritChance / 100)+(1 + rangedCritSize / 100)*(rangedCritChance / 100));
            HIB_count++;
        }
        if(ability == "MV"){
            tDam = tDam * ((1 - (techCritChance / 100))+(1 + techCritSize / 100)*(techCritChance / 100));
            MV_count++;
        }
        if(ability == "HS"){
            tDam = tDam * ((1 - rangedCritChance / 100)+(1 + rangedCritSize / 100)*(rangedCritChance / 100));
            HS_count++;
        }

        //account for all procs and stacked buffs
        if(ability == "GR"){
            proc = Proc(30);
            if(ammo_proc_CD == 0){
                ammo_proc = Proc(techCritChance);}
            if(proc == true){
                FA_CD = 0;
                proc_CD = 6;
            }
            gv_time_remaining = 15;
            grav_vortex_count += 1;
            grav_vortex_count = min(grav_vortex_count,5);
            charged_barrel_count += 1;
            charged_barrel_count = min(charged_barrel_count,5);
        }
        if(ability == "FA" && proc == true){
            proc = false;
            tDam = tDam * 1.25;
        }
        if(ability == "HIB"){
            tDam = tDam * (1+0.06*charged_barrel_count);
        }
        if((ability == "FA")&&ammo_proc_CD == 0.0){
            ammo_proc = Proc(rangedCritChance);
        }
        if((ability == "DR")&&ammo_proc_CD == 0.0){
            ammo_proc = Proc(techCritChance);
        }
        //update all cooldowns
        if(ability != "GR")
        {
            gv_time_remaining = max(gv_time_remaining-tTime,0.0);
        }
        FA_CD = max(FA_CD-tTime,0.0);
        HIB_CD = max(HIB_CD-tTime,0.0);
        DR_CD = max(DR_CD-tTime,0.0);
        MV_CD = max(MV_CD-tTime,0.0);
        RC_CD = max(RC_CD-tTime,0.0);
        RCP_CD = max(RCP_CD-tTime,0.0);
        proc_CD = max(proc_CD-tTime,0.0);
        ammo_proc_CD = max(ammo_proc_CD-tTime,0.0);
        //set cooldown for last ability
        if(ability == "FA")
        {
            FA_CD = 15;
        }
        if(ability == "HIB")
        {
            HIB_CD = 15;
        }
        if(ability == "DR")
        {
            DR_CD = 15;
        }
        if(ability == "MV")
        {
            MV_CD = 60;
        }
        //acount for enemy armor
        armorPen = 0;
        if(ui->apCellButton->isChecked()){
            armorPen += .35;
        }
        armorPen += 0.04*grav_vortex_count;
        enemyArmor = (ui->enemyArmorBox->value())*(1-armorPen);
        enemyArmorDR = Armor(enemyLevel, 0.0, enemyArmor);
        tDam = tDam * (1-enemyArmorDR);

        eDam += tDam;
        eTime += tTime;
        rAmmo = getAmmoRegened(Ammo, abil, eTime, regenTime);
        if(ammo_proc == true){
            rAmmo +=1;
            ammo_proc_CD = 3;
            ammo_proc = false;
        }
        //update Ammo and elapsed time/damage counters
        Ammo += (rAmmo - tAmmo);
        Ammo = min(max(Ammo, 0.0), 12.0);

        if(ability == "FA")
            rotationOutput+="FA , ";
        if(ability == "GR")
            rotationOutput+="GR , ";
        if(ability == "HIB")
            rotationOutput+="HIB , ";
        if(ability == "DR")
            rotationOutput+="DR , ";
        if(ability == "HS")
            rotationOutput+="HS , ";
        if(ability == "MV")
            rotationOutput+="MV , ";
        rotationOutput+= QString::number(Ammo) + " , " + QString::number(tTime) + " , " + QString::number(tDam)+ "\n";

    }
    return eDam/eTime;
}

void Commando::on_primaryBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_powerBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_critBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_alacBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_levelBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_secondaryBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_techBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_surgeBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_accBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_MHmaxBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_MHminBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_enemyLevelBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_enemyArmorBox_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_calcWeightButton_clicked()
{
    updateStatBoxes();
    getWeights();
}

void Commando::on_upgradeButton_clicked()
{
    updateStatBoxes();
    compareUpgrades();
}

void Commando::on_check4pcBox_toggled(bool checked)
{
    if(checked==true) ui->check2pcBox->setChecked(true);
}

void Commando::on_check2pcBox_toggled(bool checked)
{
    if(checked==false) ui->check4pcBox->setChecked(false);
}

void Commando::on_computeAlacrityButton_clicked()
{
    computeAlacrity();
}

void Commando::on_skillBox_1_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_skillBox_2_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_skillBox_3_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_skillBox_4_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_skillBox_5_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_skillBox_6_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_skillBox_7_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_skillBox_8_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_skillBox_9_editingFinished()
{
    updateStatBoxes();
}

void Commando::on_note1_clicked()
{
    ui->countView->clear();
    QString note1 = "*Note that Crit Size may differ from the value in game because Potent Medicine only affects heals, so does not show up on the in-game tooltip.";
    ui->countView->insertPlainText(note1);
}

void Commando::on_note2_clicked()
{
    ui->countView->clear();
    QString note2 = "**Note 2: Alacrity has complex interactions with SCC windows, resource mechanics, Effective Cost of abilities, etc.\n\n";
    note2 += "Current recommendation is for 5-7.5% Alacrity, not to exceed 8.5% for Commandos or 12.5% for Mercs. The difference is due to imbalance in their resource regen windows.  While Alacrity is not good for Mercs, it is especially bad for Commandos.\n\n";
    note2+= "Note that these limits become less of a concern as you overgear your encounters and you increase your downtime. That turns the encounter from a sustained healing to a burst healing mode with recovery times, and the increased Effective Cost is less problematic. Use your best judgment.\n\n";
    note2+= "For more information, see the following two threads on the SWTOR.com forums\n\n http://www.swtor.com/community/showthread.php?p=2900243#post2900243\n\nhttp://www.swtor.com/community/showthread.php?t=306667";
    ui->countView->insertPlainText(note2);
}

void Commando::on_saveStats_clicked()
{
    setStats();
    string filename = "Commando_stats.txt";
    ofstream fout (filename.c_str());
    fout << stats.at(AIM) << "\n" << stats.at(CUNNING) << "\n" << stats.at(CRIT)<< "\n" <<
            stats.at(SURGE) << "\n" << ui->powerBox->value() << "\n" << ui->techBox->value() << "\n" << stats.at(ALACRITY) << "\n" <<
            stats.at(LEVEL) << "\n" << stats.at(ACCURACY) << "\n" << stats.at(MH_MAX) << "\n" <<
            stats.at(MH_MIN) << "\n" << stats.at(ENEMY_LEVEL) << "\n" << stats.at(ENEMY_ARMOR) << endl;

    fout << ui->skillBox_1->value() << "\n" << ui->skillBox_2->value() << "\n" << ui->skillBox_3->value() << "\n" <<
            ui->skillBox_4->value() << "\n" << ui->skillBox_5->value() << "\n" << ui->skillBox_6->value() << "\n" <<
            ui->skillBox_7->value() << "\n" << ui->skillBox_8->value() << "\n" << ui->skillBox_9->value() << "\n" << endl;
    fout.close();
}

void Commando::Load_Stats(){
    string filename = "Commando_stats.txt";
    ifstream fin (filename.c_str());
    vector <string> inputStats(27,"0");
    int i=0;
    while(fin.good()){
        getline(fin,inputStats.at(i));
        i++;
    }
    ui->primaryBox->setValue(atoi(inputStats.at(0).c_str()));
    ui->secondaryBox->setValue(atoi(inputStats.at(1).c_str()));
    ui->critBox->setValue(atoi(inputStats.at(2).c_str()));
    ui->surgeBox->setValue(atoi(inputStats.at(3).c_str()));
    ui->powerBox->setValue(atoi(inputStats.at(4).c_str()));
    ui->techBox->setValue(atoi(inputStats.at(5).c_str()));
    ui->alacBox->setValue(atoi(inputStats.at(6).c_str()));
    ui->levelBox->setValue(atoi(inputStats.at(7).c_str()));
    ui->accBox->setValue(atoi(inputStats.at(8).c_str()));
    ui->MHmaxBox->setValue(atoi(inputStats.at(9).c_str()));
    ui->MHminBox->setValue(atoi(inputStats.at(10).c_str()));
    ui->enemyLevelBox->setValue(atoi(inputStats.at(11).c_str()));
    ui->enemyArmorBox->setValue(atoi(inputStats.at(12).c_str()));

    //set skill boxes
    ui->skillBox_1->setValue(atoi(inputStats.at(13).c_str()));
    ui->skillBox_2->setValue(atoi(inputStats.at(14).c_str()));
    ui->skillBox_3->setValue(atoi(inputStats.at(15).c_str()));
    ui->skillBox_4->setValue(atoi(inputStats.at(16).c_str()));
    ui->skillBox_5->setValue(atoi(inputStats.at(17).c_str()));
    ui->skillBox_6->setValue(atoi(inputStats.at(18).c_str()));
    ui->skillBox_7->setValue(atoi(inputStats.at(19).c_str()));
    ui->skillBox_8->setValue(atoi(inputStats.at(20).c_str()));
    ui->skillBox_9->setValue(atoi(inputStats.at(21).c_str()));

    fin.close();
}

void Commando::on_loadStats_clicked()
{
    Load_Stats();
}

void Commando::on_tree1_clicked()
{
    updateStatBoxes();
    ui->skillBox_1->setValue(3);
    ui->skillBox_2->setValue(3);
    ui->skillBox_3->setValue(1);
    ui->skillBox_4->setValue(5);
    ui->skillBox_5->setValue(2);
    ui->skillBox_6->setValue(2);
    ui->skillBox_7->setValue(2);
    ui->skillBox_8->setValue(2);
    ui->skillBox_9->setValue(2);

    //set option box labels
    ui->optionLabel_1->setText("Min. Ammo for Full Price Med Probe:");
    ui->optionBox_1->setValue(10);
    ui->optionLabel_2->setText("Min. Ammo for Adv. Probe during Supercharge Cells:");
    ui->optionBox_2->setValue(5);

}

void Commando::on_tree2_clicked()
{
    updateStatBoxes();
    ui->csCellButton->setEnabled(false);
    ui->apCellButton->setChecked(true);
    ui->apCellButton->setEnabled(true);
    ui->pCellButton->setEnabled(true);
    ui->pCellButton->setText("Plasma Cell (NYI)");

    ui->calcHPSButton->setText("Calculate DPS");
    ui->HPS_label->setText("DPS:");
    ui->upg1Label->setText("Item 1 DPS:");
    ui->upg2Label->setText("Item 2 DPS:");
    ui->computeAlacrityButton->setText("Compute Alacrity Curves***");

    //set skill tree options
    ui->set2pcLabel->setText("Increases the Critical Chance of Grav Round by 15%");
    ui->set4pcLabel->setText("Reduces the cost of Hight Impact Bolt by 1.");
    ui->skill_label_1->setText("Ironsights (9% Aim)");
    ui->skill_label_2->setText("Field Training (6% Tech Crit)");
    ui->skill_label_3->setText("Reserve Round (15s off RCP CD)");
    ui->skill_label_4->setText("Target Lock (3% Accuracy)");
    ui->skill_label_5->setText("First Responder (5% Alacrity)");
    ui->skill_label_6->setText("Weapon Calibration (4% Alacrity)");
    ui->skill_label_7->setText("Cell Capacitor (RC Ammo)");
    ui->skill_label_8->setText("Havoc Rounds (6% Damage to Rounds)");
    ui->skill_label_9->setText("Demolition Round");
    //ui->skillBox_9->setVisible(false);
    ui->skillBox_1->setMaximum(3);
    ui->skillBox_2->setMaximum(3);
    ui->skillBox_3->setMaximum(2);
    ui->skillBox_4->setMaximum(3);
    ui->skillBox_5->setMaximum(2);
    ui->skillBox_6->setMaximum(2);
    ui->skillBox_7->setMaximum(2);
    ui->skillBox_8->setMaximum(2);
    ui->skillBox_9->setMaximum(1);

    ui->skillBox_1->setValue(3);
    ui->skillBox_2->setValue(3);
    ui->skillBox_3->setValue(2);
    ui->skillBox_4->setValue(3);
    ui->skillBox_5->setValue(2);
    ui->skillBox_6->setValue(2);
    ui->skillBox_7->setValue(2);
    ui->skillBox_8->setValue(2);
    ui->skillBox_9->setValue(1);

    //set option box labels
    ui->optionLabel_1->setText("Use Mortar Volley with RCP when Ammo drops below:");
    ui->optionBox_1->setValue(10);
    ui->optionLabel_2->setText("When RC is on cooldown, use HS when Ammo drops below:");
    ui->optionBox_2->setValue(9);
    ui->optionBox_4->setVisible(true);
    ui->optionLabel_4->setVisible(true);
    ui->optionBox_5->setVisible(true);
    ui->optionLabel_5->setVisible(true);
    ui->note3->setVisible(true);
}

void Commando::on_tree3_clicked()
{
    updateStatBoxes();
}

void Commando::on_note3_clicked()
{
    ui->countView->clear();
    QString note1 = "Note 3: Due to the random nature (RNG) of the numerous procs in the Gunnery tree, multiple runs should be averaged to smooth out randomness.  The more runs, the longer it will take. Currently this field has a range of 1-10000 runs.";
    note1 += "\n\nThe output windows will only display the results of the last rotation, as an example set of how the rotation looked for a given set of RNG values.";
    note1 += "\n\nBe careful setting this value too high, as it will cause the Compute Alacrity, Stat Weight and Upgrade Calculator buttons to take a long time to process.  The Compute Alacrity button will require 79 times as many rotations, so setting it to 1,000 will require 79,000 rotations. A setting of 10,000 will require 790,000 rotations...";
    note1 += "\n\nTo remove variability in the outputs and allow proper comparison, the same RNG seed is fed to all rotations at the start.  This makes them the same on display to you, but internally they vary each time.";
    ui->countView->insertPlainText(note1);
    updateStatBoxes();
}



void Commando::on_sustainedButton_clicked()
{
    ui->fixedCastButton->setEnabled(true);
    ui->numCasts->setMaximum(3000.00);
    ui->numCasts->setValue(300.00);
    if(ui->tree1->isChecked()){
        ui->optionBox_2->setValue(4);

        ui->optionBox_3->setValue(5);
    }
    if(ui->tree2->isChecked()){
        ui->optionBox_5->setEnabled(true);
        ui->optionBox_2->setValue(9);
        ui->optionBox_3->setValue(5);
    }
}

void Commando::on_burstButton_clicked()
{
    ui->fixedCastButton->setEnabled(false);
    ui->fixedTimeButton->setChecked(true);
    ui->numCasts->setMaximum(30.00);
    ui->numCasts->setValue(30.00);
    if(ui->tree1->isChecked()){
        ui->optionBox_2->setValue(4);
        ui->optionBox_3->setValue(5);
    }
    if(ui->tree2->isChecked()){
        ui->optionBox_5->setEnabled(false);
        ui->optionBox_2->setValue(0);
        ui->optionBox_3->setValue(0);
    }

}
